package com.gantang.gax.engine.utils;


import cn.hutool.core.util.StrUtil;
import com.gantang.gax.engine.model.EngineCreator;
import com.gantang.gax.engine.model.VariableGroup;

import java.util.*;

/**
 * 很多特征族和特征值的命名不规范，导致推导引擎在解析表达式时出错
 * 该工具提供统一的家族/值/表达式命名规范转换
 * <p>
 * 家族从  FAM0001 开始编号，最多支持 9999个家族
 * 特征从  FEA000001 开始编号，同一个家族下最多支持 999999个特征
 * <p>
 * 规则约束表达式首先按照关键分割符进行划分，然后特征值统一进行替换
 * <p>
 * 出错后的核心原因也支持重新替换回原特征族和特征值的名称
 */
public class NameConversionTool {

    private Integer familyCount = 0;
    private Integer featureCount = 0;
    private Integer miscCount = 0;

    private static final String FAMILY_PREFIX = "FAM";
    private static final Integer FAMILY_SEQ_LENGTH = 4;

    private static final String FEATURE_PREFIX = "FEA";
    private static final Integer FEATURE_SEQ_LENGTH = 6;

    private static final String MISC_PREFIX = "MISC";
    private static final Integer MISC_SEQ_LENGTH = 6;

    //private static final String[]  expressionSplitter = new String[]{"<",">","=","(",")","+","*","&","|","!"};
    private static final String expressionSplitter = "<>=()+*&|!~";

    private Map<String, String> nameMap = new HashMap<>();
    private Map<String, String> familyNameA2BMap = new HashMap<>();  //A 代表外部输入定义的编码名称  B 代表内部转化后的标准化编码名称
    private Map<String, String> familyNameB2AMap = new HashMap<>();

    private Map<String, String> featureNameA2BMap = new HashMap<>();
    private Map<String, String> featureNameB2AMap = new HashMap<>();

    public Map<String, List<String>> familyNameConvert(Map<String, List<String>> familyMap) {
        Map<String, List<String>> convertedFamilyMap = new HashMap<>();
        familyMap.forEach((familyAName, featureAList) -> {
            String familyBName = generateFamilyName(familyAName);
            List<String> featureBList = new ArrayList<>();
            for (String featureAName : featureAList) {
                featureBList.add(generateFeatureName(featureAName));
            }
            convertedFamilyMap.put(familyBName, featureBList);
        });
        return convertedFamilyMap;
    }

    public Map<String, List<String>> familyNameConvert2(Map<String, List<VariableGroup.Variable>> familyMap) {
        Map<String, List<String>> convertedFamilyMap = new HashMap<>();
        familyMap.forEach((familyAName, featureAList) -> {
            String familyBName = generateFamilyName(familyAName);
            List<String> featureBList = new ArrayList<>();
            for (VariableGroup.Variable featureAName : featureAList) {
                featureBList.add(generateFeatureName(featureAName.getCode()));
            }
            convertedFamilyMap.put(familyBName, featureBList);
        });
        return convertedFamilyMap;
    }

    public List<String> rulesConvert(List<String> rules) {
        List<String> convertedRules = new ArrayList<>();
        for (String rule : rules) {
            convertedRules.add(ruleConvert(rule));
        }
        return convertedRules;
    }

    public String ruleConvert(String rule) {
        StringTokenizer st = new StringTokenizer(rule, expressionSplitter, true);
        StringBuffer convertedRule = new StringBuffer();
        while (st.hasMoreElements()) {
            String token = st.nextToken();
            String result = nameMap.get(token);
            if (null == result) {
                result = token;
            }
            convertedRule.append(result);
        }
        return convertedRule.toString();
    }

    public String anyNameConvert(String name) {

        if (StrUtil.isBlank(name)) {
            return name;
        }

        String bName = nameMap.get(name);
        if (null == bName) {
            miscCount++;
            // 使用Hutool的StrUtil.padPre方法来填充字符串以替换StringUtils.leftPad
            bName = MISC_PREFIX + StrUtil.padPre(String.valueOf(miscCount), MISC_SEQ_LENGTH, '0');
            nameMap.put(name, bName);
            nameMap.put(bName, name);
        }
        return bName;
    }

    public Map<String, String> featureDisplayNameConvert(Map<String, String> featureNameMap) {
        Map<String, String> convertedFeatureNameMap = new HashMap<>();

        //首先将所有标准化的特征描述编码都先将特征值转换成外部名称
        convertedFeatureNameMap.putAll(featureNameB2AMap);

        //如果外部还有其它定义的显示名称，则进一步替换
        if (null != featureNameMap) {
            featureNameMap.forEach((feature, featureDisplayName) -> {
                String convertedFeature = nameMap.get(feature);
                if (StrUtil.isBlank(convertedFeature)) {
                    convertedFeature = feature;
                }
                convertedFeatureNameMap.put(convertedFeature, featureDisplayName);
            });
        }

        return convertedFeatureNameMap;
    }

    public String getNameMapping(String name) {
        if (StrUtil.isBlank(name)) {
            return name;
        }
        return nameMap.getOrDefault(name, name);
    }

    public List<String> getNameMappingByList(List<String> nameList) {
        List<String> convertedNameList = new ArrayList<>();
        for (String name : nameList) {
            convertedNameList.add(getNameMapping(name));
        }
        return convertedNameList;
    }

    public List<List<String>> getNameMappingByNestedList(List<List<String>> nestedNameList) {
        List<List<String>> convertedNestedNameList = new ArrayList<>();
        for (List<String> nameList : nestedNameList) {
            convertedNestedNameList.add(getNameMappingByList(nameList));
        }
        return convertedNestedNameList;
    }

    public Map<String, List<String>> getNameMappingByMapList(Map<String, List<String>> nameMapList) {
        Map<String, List<String>> convertedNameMapList = new HashMap<>();
        nameMapList.forEach((keyName, nameList) -> {
            convertedNameMapList.put(getNameMapping(keyName), getNameMappingByList(nameList));
        });
        return convertedNameMapList;
    }

    private String generateFamilyName(String familyAName) {
        String familyBName = nameMap.get(familyAName);
        if (null == familyBName) {
            familyCount++;
            // 使用Hutool的StrUtil.padPre方法来填充字符串
            familyBName = FAMILY_PREFIX + StrUtil.padPre(String.valueOf(familyCount), FAMILY_SEQ_LENGTH, '0');
            nameMap.put(familyAName, familyBName);
            nameMap.put(familyBName, familyAName);

            familyNameA2BMap.put(familyAName, familyBName);
            familyNameB2AMap.put(familyBName, familyAName);
        }
        return familyBName;
    }

    public String generateFeatureName(String featureAName) {
        String featureBName = nameMap.get(featureAName);
        if (null == featureBName) {
            featureCount++;
            // 使用Hutool的StrUtil.padPre方法来替代StringUtils.leftPad
            featureBName = FEATURE_PREFIX + StrUtil.padPre(String.valueOf(featureCount), FEATURE_SEQ_LENGTH, '0');
            nameMap.put(featureAName, featureBName);
            nameMap.put(featureBName, featureAName);

            featureNameA2BMap.put(featureAName, featureBName);
            featureNameB2AMap.put(featureBName, featureAName);
        }
        return featureBName;
    }
}
